#include "../include/zemaphore.h"
#include <header.h>

/***
 * wait()调用有一个参数，它是互斥量。
 * 它假定在 wait()调用时，这个互斥量是已上锁状态。
 * wait()的职责是释放锁，并让调用线程休眠（原子地）。
 * 当线程被唤醒时（在另外某个线程发信号给它后），
 * 它必须重新获取锁，再返回调用者。
*/

// 阻塞 = java中的挂起
// only one thread can call this 
void zem_init(zem_t *s, int value) { 
    s->value = value;
    pthread_cond_init(&s->cond, NULL);
    pthread_mutex_init(&s->lock, NULL);
} 


// P
void zem_wait(zem_t *s){
    // 自旋，会分配时间片，但是线程此时还是阻塞态
    pthread_mutex_lock(&s->lock);
    /**
     * 如果用if判断则多个消费者可能会有问题：
     * 若thread1已经wait，且释放锁;
     * 但此时thread2运行，因为pthread_mutex_lock()底层为自旋机制，
     * 所以获得锁之后直接跳过while执行value--，thread1再执行则会有问题！
    */
    while (s->value <= 0){
        // 一直阻塞，不会分配时间片，线程为阻塞态，但是等待操作系统来唤醒
        pthread_cond_wait(&s->cond, &s->lock); 
    }
    s->value--; 
    pthread_mutex_unlock(&s->lock); 
} 

// V
void zem_post(zem_t *s) {
    pthread_mutex_lock(&s->lock); 
    s->value++; 
    pthread_cond_signal(&s->cond); 
    pthread_mutex_unlock(&s->lock); 
}

/**
 * 不能free(zem_t),因为有可能是在栈上创建的
*/
void zem_destory(zem_t *s){
    pthread_cond_destroy(&s->cond);
    pthread_mutex_destroy(&s->lock);
}

/**
 * 动态库制作
 * gcc -c zemaphore.c -o zemaphore.o -fpic -I zemaphore.h
 * gcc -shared zemaphore.o -o libzemaphore.so
 * cp libzemaphore.so /usr/lib64/libzemaphore.so
 * 
 * 
 * #使用时候要加-lzemaphore
 * gcc main.c -o main -lzemaphore
*/

